
package com.hlkj.pay.controller.merchant;

import java.math.BigDecimal;
import java.util.*;

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.pojo.PageResult;
import com.hlkj.framework.common.util.collection.CollectionUtils;
import com.hlkj.framework.common.util.id.IdUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.IAcctAccountAppService;
import com.hlkj.pay.app.order.IAcctOrderAppService;
import com.hlkj.pay.common.OpenApiResultCode;
import com.hlkj.pay.controller.BaseController;
import com.hlkj.pay.dto.fund.FundAccountQueryDto;
import com.hlkj.pay.dto.fund.FundConfigQueryDto;
import com.hlkj.pay.dto.fund.MerchantFundPageDto;
import com.hlkj.pay.dto.order.PayOrderFundQueryDto;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.infrastructure.model.merchant.fund.MerchantFundAccountBindDO;
import com.hlkj.pay.infrastructure.model.merchant.fund.MerchantFundAccountConfigDO;
import com.hlkj.pay.infrastructure.model.order.OrderFundDO;
import com.hlkj.pay.infrastructure.model.order.OrderFundDetailDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.service.merchant.IMerchantFundAccountService;
import com.hlkj.pay.service.order.IPayOrderFundService;
import com.hlkj.pay.service.order.IPayOrderService;
import com.hlkj.pay.util.OrderCodeUtil;
import com.hlkj.pay.vo.merchant.req.fund.req.MerchantFundPageReq;
import com.hlkj.pay.vo.merchant.req.fund.req.OrderFundPageReq;
import com.hlkj.pay.vo.merchant.req.fund.resp.FundAccountListResp;
import com.hlkj.pay.vo.merchant.resp.app.MerchantFundListResp;
import com.hlkj.pay.vo.openapi.fund.req.*;
import com.hlkj.pay.vo.openapi.fund.resp.OpenApiFundAccountBindListResp;
import com.hlkj.pay.vo.openapi.fund.resp.OpenApiFundAccountBindResp;
import com.hlkj.pay.vo.openapi.fund.resp.OpenApiFundAccountResp;
import com.hlkj.pay.vo.openapi.order.resp.AcctPayOrderApiResp;
import com.hlkj.pay.vo.order.req.AcctOrderQueryParamReq;
import com.hlkj.pay.vo.order.req.AcctPayOrderParamReq;
import com.hlkj.pay.vo.order.req.MerAcctPayOrderParamReq;
import com.hlkj.pay.vo.order.req.OrderAccount;
import com.hlkj.pay.vo.order.resp.PayOrderDetailResp;
import com.hlkj.pay.vo.order.resp.acct.AcctPayOrderResp;
import com.hlkj.pay.vo.order.resp.acct.OrderFundListResp;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/10/09 11:25
 */
@Tag(name = "汇分账")
@RestController
@RequestMapping("/v1/merchant/acct")
@RequiredArgsConstructor
@Slf4j
public class MerchantFundController extends BaseController {

    private final IAcctOrderAppService acctOrderAppService;

    private final IPayOrderFundService payOrderFundService;

    private final IPayOrderService payOrderService;

    private final IAcctAccountAppService acctAccountAppService;

    private final IMerchantFundAccountService merchantFundAccountService;

    private final  OrderCodeUtil orderCodeUtil;

    @Operation(summary = "分账订单查询")
    @GetMapping("/order/page")
    CommonResult<PageResult<OrderFundListResp>> queryAcctOrderPage(OrderFundPageReq orderFundPageReq) {
        PayOrderFundQueryDto orderFundQueryDto = BeanUtil.copyProperties(orderFundPageReq, PayOrderFundQueryDto.class);
        processQueryDate(orderFundPageReq, orderFundQueryDto);
        PageResult<OrderFundDO> page = payOrderFundService.queryPage(orderFundQueryDto);
        List<OrderFundDO> list = page.getList();
        if (CollectionUtils.isEmpty(list)) {
            return buildPageResult(page, Collections.emptyList());
        }
        List<OrderFundListResp> merchantReportInfoListResps = BeanUtil.copyToList(list, OrderFundListResp.class);
        for(OrderFundListResp orderFundListResp:merchantReportInfoListResps){
            PayOrderDO payOrderDO = payOrderService.queryPayOrder(orderFundListResp.getPayOrderNo());
            PayOrderDetailResp payOrderDetailResp = BeanUtil.copyProperties(payOrderDO,PayOrderDetailResp.class);
            processOrder(payOrderDetailResp);
            orderFundListResp.setPayOrder(payOrderDetailResp);
        }
        return buildPageResult(page, merchantReportInfoListResps);
    }

    @Operation(summary = "分账重新提交")
    @PostMapping("/order/retry")
    CommonResult<AcctPayOrderApiResp> retry(@Validated @RequestBody MerAcctPayOrderParamReq paramReqParams) {
        AcctPayOrderParamReq acctPayOrderParamReq = BeanUtil.copyProperties(paramReqParams,AcctPayOrderParamReq.class);
        acctPayOrderParamReq.setMchAcctOrderNo(orderCodeUtil.orderNo("M",1));
        acctPayOrderParamReq.setAcctInfos(paramReqParams.getAcctInfos());
        acctPayOrderParamReq.setAccRetry(1);
        acctPayOrderParamReq.setOldBatchNo(paramReqParams.getBatchNo());
        CommonResult<AcctPayOrderApiResp> payOrderRespCommonResult = acctOrderAppService.submitAcctOrder(acctPayOrderParamReq);
        if(payOrderRespCommonResult.getCode() == OpenApiResultCode.MERCHANT_PAY_ORDER_FUND_ERROR.getCode()){
            payOrderRespCommonResult.setCode(200);
        }
        return payOrderRespCommonResult;
    }


    @Operation(summary = "分账重新批量提交")
    @PostMapping("/order/batchRetry")
    CommonResult<Map<String,Object>> batchRetry(@Validated @RequestBody List<MerAcctPayOrderParamReq> paramReqParams) {
        Map<String,Object>  result = new HashMap<>();
        for(MerAcctPayOrderParamReq merAcctPayOrderParamReq:paramReqParams){
            // 判断订单是否存在
            if(StrUtil.isEmpty(merAcctPayOrderParamReq.getPayOrderNo())){
                log.info("订单号不存在：{}", JSONUtil.toJsonStr(merAcctPayOrderParamReq));
                continue;
            }
            PayOrderDO payOrderDO = payOrderService.queryPayOrderNoCache(merAcctPayOrderParamReq.getPayOrderNo());
            if(payOrderDO == null){
                log.info("订单号:{} 数据不存在：{}",merAcctPayOrderParamReq.getPayOrderNo(), JSONUtil.toJsonStr(merAcctPayOrderParamReq));
                continue;
            }

            // 判断订单是否存在分账信息
            List<OrderFundDetailDO> fundDetailDOList = payOrderFundService.queryPayAcctInfo(merAcctPayOrderParamReq.getPayOrderNo());
            if(CollUtil.isNotEmpty(fundDetailDOList)){
                log.info("订单号:{} 存在分账详情数据：{}",merAcctPayOrderParamReq.getPayOrderNo(), JSONUtil.toJsonStr(fundDetailDOList));
                result.put(merAcctPayOrderParamReq.getPayOrderNo(),JSONUtil.toJsonStr(fundDetailDOList));
                continue;
            }

            // 为空则获取 获取商户预设默认分账数据局
            List<OrderAccount> orderAccountList = merAcctPayOrderParamReq.getAcctInfos();
            if(CollUtil.isEmpty(orderAccountList)){
                List<MerchantFundAccountBindDO> merchantFundAccountBindList = merchantFundAccountService.queryAccountBindList(payOrderDO.getMchChannelCode(), CommonEnum.YES_NO_TYPE.YES,
                        CommonEnum.YES_NO_TYPE.YES);
                if (org.springframework.util.CollectionUtils.isEmpty(merchantFundAccountBindList)) {
                    log.info("payAcctOrder 商户 预设默认分账数据不存在 payOrderNo:{}", payOrderDO.getPayOrderNo());
                    continue;
                }
                orderAccountList = new ArrayList<>();
                for(MerchantFundAccountBindDO merchantFundAccountBindDO:merchantFundAccountBindList){
                    OrderAccount orderAccount = new OrderAccount();
                    orderAccount.setAccountNo(merchantFundAccountBindDO.getAccountNo());
                    orderAccount.setName(merchantFundAccountBindDO.getName());
                    orderAccount.setDescription("系统分账");
                    if(merchantFundAccountBindDO.getD0() == null){
                        orderAccount.setPeriodType(0);
                    }else{
                        orderAccount.setPeriodType(merchantFundAccountBindDO.getD0());
                    }

                    if(payOrderDO.getAmount() != null && merchantFundAccountBindDO.getRate() != null){
                        orderAccount.setAmount(NumberUtil.roundStr(payOrderDO.getAmount().multiply(merchantFundAccountBindDO.getRate()).divide(new BigDecimal(100)).doubleValue(),2));
                    }
                    orderAccountList.add(orderAccount);
                }
            }
            // 重新提交分账信息
            AcctPayOrderParamReq acctPayOrderParamReq = BeanUtil.copyProperties(merAcctPayOrderParamReq,AcctPayOrderParamReq.class);
            acctPayOrderParamReq.setMchAcctOrderNo(IdUtil.fastSimpleUUID());
            acctPayOrderParamReq.setAcctInfos(orderAccountList);
            acctPayOrderParamReq.setAccRetry(1);
            CommonResult<AcctPayOrderApiResp> payOrderRespCommonResult = acctOrderAppService.submitAcctOrder(acctPayOrderParamReq);
            result.put(merAcctPayOrderParamReq.getPayOrderNo(),payOrderRespCommonResult);
        }
        return CommonResult.success(result);
    }

    @Operation(summary = "分账详情删除")
    @GetMapping("/order/detail/delete")
    CommonResult<String> delete(@RequestParam(value = "batchNo") String batchNo) {
        CommonResult<String> payOrderRespCommonResult = acctOrderAppService.delAcctDetail(batchNo);
        return payOrderRespCommonResult;
    }

    @Operation(summary = "分账订单查询")
    @GetMapping("/order/detail")
    CommonResult<AcctPayOrderResp> queryAcctOrder(@RequestParam(value = "batchNo") String batchNo) {
        AcctOrderQueryParamReq acctOrderQueryParamReq = new AcctOrderQueryParamReq();
        acctOrderQueryParamReq.setBatchNo(batchNo);
        CommonResult<AcctPayOrderResp> commonResult = acctOrderAppService.queryAcctOrder(acctOrderQueryParamReq);
        if(!commonResult.isSuccess()){
           return commonResult;
        }
        AcctPayOrderResp acctPayOrderResp = commonResult.getData();
        PayOrderDO payOrderDO = payOrderService.queryPayOrder(acctPayOrderResp.getPayOrderNo());
        PayOrderDetailResp payOrderDetailResp = BeanUtil.copyProperties(payOrderDO,PayOrderDetailResp.class);
        processOrder(payOrderDetailResp);
        commonResult.getData().setPayOrder(payOrderDetailResp);
        return commonResult;
    }

    @Operation(summary = "通过平台订单号查询分账信息")
    @GetMapping("/order/list")
    CommonResult<List<OrderFundDetailDO>> queryList(@RequestParam(value = "payOrderNo") String payOrderNo) {
        return CommonResult.success(payOrderFundService.queryPayAcctInfo(payOrderNo));
    }

    @Operation(summary = "分账完结")
    @GetMapping("/order/finish")
    CommonResult<AcctPayOrderResp> finishAcctOrder(@RequestParam(value = "batchNo") String batchNo) {
        AcctOrderQueryParamReq acctOrderQueryParamReq = new AcctOrderQueryParamReq();
        acctOrderQueryParamReq.setBatchNo(batchNo);
        return acctOrderAppService.finishAcctOrder(acctOrderQueryParamReq);
    }

    @Operation(summary = "订单批量结算")
    @PostMapping("/order/settleConfirm")
    CommonResult<String> settleConfirm(@RequestBody List<String> payOrderNoList) {
        return acctOrderAppService.settleConfirm(payOrderNoList);
    }

    @Operation(summary = "分账接收方分页查询")
    @GetMapping("/account/page")
    CommonResult<FundAccountListResp> fundAccountPage(MerchantFundPageReq merchantFundPageReq) {
        FundAccountQueryDto fundQueryDto = BeanUtil.copyProperties(merchantFundPageReq, FundAccountQueryDto.class);
        processQueryDate(merchantFundPageReq, fundQueryDto);
        PageResult<MerchantFundPageDto> page = merchantFundAccountService.queryPage(fundQueryDto);
        List<MerchantFundPageDto> list = page.getList();
        if (CollectionUtils.isEmpty(list)) {
            return buildPageResult(page, Collections.emptyList());
        }
        List<FundAccountListResp> merchantReportInfoListResps = BeanUtil.copyToList(list, FundAccountListResp.class);
        processProvideList(merchantReportInfoListResps);
        return buildPageResult(page, merchantReportInfoListResps);
    }

    @Operation(summary = "分账接收方删除")
    @GetMapping("/account/delete")
    CommonResult<Void> deleteAccount(@RequestParam(value = "id") Long id) {
        merchantFundAccountService.delAccount(id);
        return CommonResult.success();
    }

    @Operation(summary = "分账接收方列表")
    @GetMapping("/account/list")
    CommonResult<List<FundAccountListResp>> fundAccountList(MerchantFundPageReq merchantFundPageReq) {
        FundAccountQueryDto fundQueryDto = BeanUtil.copyProperties(merchantFundPageReq, FundAccountQueryDto.class);
        processQueryDate(merchantFundPageReq, fundQueryDto);
        List<MerchantFundPageDto> list = merchantFundAccountService.queryList(fundQueryDto);
        if (CollectionUtils.isEmpty(list)) {
            return CommonResult.success(Collections.emptyList());
        }
        return CommonResult.success(BeanUtil.copyToList(list, FundAccountListResp.class));
    }

    @Operation(summary = "分账接收方录入")
    @PostMapping("/account/submit")
    CommonResult<OpenApiFundAccountResp> submitAccount(@RequestBody OpenApiFundAccountSubmitReq fundAccountReq) {
        if (MerchantEnum.MERCHANT_TYPE.PERSONAL.getCode().equals(fundAccountReq.getMerchantAccessInfo().getType())) {
            fundAccountReq.getMerchantAccessInfo().setMerchantAccessLicense(null);
        }
        fundAccountReq.setMchOrderNo(IdUtils.getSnowflakeNextIdStr());
        return acctAccountAppService.submitAccount(fundAccountReq);
    }

    @Operation(summary = "分账接收方更新")
    @PostMapping("/account/update")
    CommonResult<OpenApiFundAccountResp> updateAccountCard(@Validated @RequestBody OpenApiFundAccountUpdateReq fundAccountReq) {
        return acctAccountAppService.updateAccountCard(fundAccountReq);
    }

    @Operation(summary = "分账关系绑定")
    @PostMapping("/account/bind")
    CommonResult<Void> accountBind(@Validated @RequestBody OpenApiFundAccountBindReq fundAccountBindReq) {
        return acctAccountAppService.accountBind(fundAccountBindReq);
    }

    @Operation(summary = "分账关系解绑")
    @PostMapping("/account/unbind")
    CommonResult<Void> accountUnBind(@Validated @RequestBody OpenApiFundAccountBindReq accountBindReq) {
        return acctAccountAppService.accountUnBind(accountBindReq);
    }

    @Operation(summary = "分账接收方详情")
    @GetMapping("/account/detail")
    CommonResult<OpenApiFundAccountSubmitReq> accountDetail(@RequestParam("id") Long id) {
        return acctAccountAppService.queryAccountById(id);
    }

    @Operation(summary = "分账关系状态更新")
    @PostMapping("/account/bind/status")
    CommonResult<Void> updateStatus(@RequestBody OpenApiFundAccountBindStatusReq fundAccountReq) {
        return acctAccountAppService.updateStatus(fundAccountReq);
    }

    @Operation(summary = "分账关系-分账类型更新")
    @PostMapping("/account/bind/type")
    CommonResult<Void> updateStatus(@RequestBody OpenApiFundAccountBindTypeReq fundAccountReq) {
        return acctAccountAppService.updateBindType(fundAccountReq);
    }

    @Operation(summary = "分账关系查询")
    @GetMapping("/account/query")
    CommonResult<OpenApiFundAccountBindResp> accountQuery(@RequestParam(value = "mchChannelCode") String mchChannelCode) {
        OpenApiFundAccountBindResp openApiFundAccountBindResp = new OpenApiFundAccountBindResp();
        openApiFundAccountBindResp.setMchChannelCode(mchChannelCode);
        List<MerchantFundAccountBindDO> merchantFundAccountBinds = merchantFundAccountService.queryAccountBindList(mchChannelCode);
        if (CollectionUtils.isNotEmpty(merchantFundAccountBinds)) {
            openApiFundAccountBindResp.setAccountList(JsonUtils.toJsonStringNotNull(BeanUtil.copyToList(merchantFundAccountBinds, OpenApiFundAccountBindListResp.class)));
        }
        acctAccountAppService.queryAccountBindList(mchChannelCode);
        return CommonResult.success(openApiFundAccountBindResp);
    }

    @Operation(summary = "分账配置分页")
    @PostMapping("/config/page")
    CommonResult<PageResult<MerchantFundListResp>> configPage(@RequestBody FundConfigQueryDto fundQueryDto) {
        PageResult<MerchantFundAccountConfigDO> page = acctAccountAppService.accountConfigPage(fundQueryDto);
        List<MerchantFundAccountConfigDO> list = page.getList();
        if (CollectionUtils.isEmpty(list)) {
            return buildPageResult(page, Collections.emptyList());
        }
        List<MerchantFundListResp> merchantAppChannelListResps = BeanUtil.copyToList(list, MerchantFundListResp.class);
        for(MerchantFundListResp merchantFundListResp:merchantAppChannelListResps){
            processFundAccount(merchantFundListResp);
        }
        return buildPageResult(page, merchantAppChannelListResps);
    }

    @Operation(summary = "分账配置新增")
    @PostMapping("/config/add")
    CommonResult<Void> configAdd(@Validated @RequestBody OpenApiFundAccountConfigReq fundAccountConfigReq) {
        return acctAccountAppService.accountConfigAdd(fundAccountConfigReq);
    }

    @Operation(summary = "分账配置修改")
    @PostMapping("/config/update")
    CommonResult<Void> configUpdate(@Validated @RequestBody OpenApiFundAccountConfigReq fundAccountConfigReq) {
        return acctAccountAppService.accountConfigUpdate(fundAccountConfigReq);
    }

    @Operation(summary = "分账配置详情")
    @GetMapping("/config/detail")
    CommonResult<MerchantFundListResp> configDetail(@RequestParam(value = "fundConfigId") Long id) {
        CommonResult<MerchantFundAccountConfigDO> commonResult = acctAccountAppService.accountConfigDetail(id);
        MerchantFundListResp merchantFundListResp = new MerchantFundListResp();
        if(commonResult.isSuccess() && commonResult.getData() != null){
            merchantFundListResp = BeanUtil.copyProperties(commonResult.getData(),MerchantFundListResp.class);
            processFundAccount(merchantFundListResp);
        }
        return CommonResult.success(merchantFundListResp);
    }

    @Operation(summary = "分账配置删除")
    @GetMapping("/config/delete")
    CommonResult<Void> configDelete(@RequestParam(value = "fundConfigId") Long id) {
        return acctAccountAppService.accountConfigDelete(id);
    }
}
